package cn.iocoder.yudao.module.system.controller.admin.gugu;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.controller.admin.gugu.vo.CollegeRecommendReqVO;
import cn.iocoder.yudao.module.system.controller.admin.gugu.vo.CollegeRecommendRespVO;
import cn.iocoder.yudao.module.system.service.gugu.CollegeRecommendationService;
import cn.iocoder.yudao.module.system.util.gugu.ResponseUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.concurrent.*;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

/**
 * 管理后台 - 智能推荐大学控制器
 *
 * @author 芋道源码
 */
@Tag(name = "管理后台 - 智能推荐大学")
@RestController
@RequestMapping("/system/college-recommendation")
@Validated
@Slf4j
public class CollegeRecommendationController {

    @Resource
    private CollegeRecommendationService collegeRecommendationService;

    /**
     * 异步处理线程池 - 专门用于推荐计算
     */
    private final ExecutorService recommendationExecutor = new ThreadPoolExecutor(
        4, 8, 60L, TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(100),
        r -> new Thread(r, "recommendation-" + System.currentTimeMillis()),
        new ThreadPoolExecutor.CallerRunsPolicy()
    );

    /**
     * 推荐请求超时时间（秒）
     */
    private static final long RECOMMENDATION_TIMEOUT = 30;

    @PostMapping("/recommend")
    @Operation(summary = "智能推荐大学（优化版 - 异步处理）")
    public DeferredResult<CommonResult<CollegeRecommendRespVO>> recommendColleges(@Valid @RequestBody CollegeRecommendReqVO reqVO) {
        log.info("智能推荐大学请求（异步）：{}", reqVO);

        // 创建异步结果对象，设置30秒超时
        DeferredResult<CommonResult<CollegeRecommendRespVO>> deferredResult =
            new DeferredResult<>(RECOMMENDATION_TIMEOUT * 1000L);

        // 设置超时处理
        deferredResult.onTimeout(() -> {
            log.warn("推荐请求超时，参数：{}", reqVO);
            deferredResult.setResult(ResponseUtils.timeout("推荐计算超时，请稍后重试或减少查询范围"));
        });

        // 设置异常处理
        deferredResult.onError((throwable) -> {
            log.error("推荐请求异常", throwable);
            deferredResult.setResult(ResponseUtils.serverError("推荐服务异常：" + throwable.getMessage()));
        });

        // 异步执行推荐计算
        CompletableFuture<CommonResult<CollegeRecommendRespVO>> future = CompletableFuture.supplyAsync(() -> {
            try {
                // 优化请求参数，限制数据量
                CollegeRecommendReqVO optimizedReqVO = optimizeRequestParameters(reqVO);

                long startTime = System.currentTimeMillis();
                CollegeRecommendRespVO result = collegeRecommendationService.recommendColleges(optimizedReqVO);
                long endTime = System.currentTimeMillis();

                log.info("推荐计算完成，耗时：{}ms，结果数量：{}",
                    endTime - startTime, result.getList().size());

                return ResponseUtils.success(result);

            } catch (Exception e) {
                log.error("异步推荐计算失败", e);
                return ResponseUtils.serverError("推荐服务异常：" + e.getMessage());
            }
        }, recommendationExecutor);

        future.whenComplete((result, throwable) -> {
            if (throwable != null) {
                log.error("异步推荐执行异常", throwable);
                deferredResult.setResult(ResponseUtils.serverError("推荐服务异常：" + throwable.getMessage()));
            } else {
                deferredResult.setResult(result);
            }
        });

        return deferredResult;
    }

    @PostMapping("/recommend-fast")
    @Operation(summary = "快速推荐大学（同步版本，限制数据量）")
    public CommonResult<CollegeRecommendRespVO> recommendCollegesFast(@Valid @RequestBody CollegeRecommendReqVO reqVO) {
        log.info("快速推荐大学请求：{}", reqVO);

        try {
            // 强制优化参数，确保快速响应
            CollegeRecommendReqVO fastReqVO = createFastRequestParameters(reqVO);

            long startTime = System.currentTimeMillis();
            CollegeRecommendRespVO result = collegeRecommendationService.recommendColleges(fastReqVO);
            long endTime = System.currentTimeMillis();

            log.info("快速推荐完成，耗时：{}ms，结果数量：{}",
                endTime - startTime, result.getList().size());

            return ResponseUtils.success(result);

        } catch (Exception e) {
            log.error("快速推荐失败", e);
            return ResponseUtils.serverError("推荐服务异常：" + e.getMessage());
        }
    }

    @PostMapping("/recommend-with-user")
    @Operation(summary = "智能推荐大学（带用户ID）")
    public CommonResult<CollegeRecommendRespVO> recommendCollegesWithUser(
            @Valid @RequestBody CollegeRecommendReqVO reqVO,
            @Parameter(description = "用户ID") @RequestParam(required = false) Long userId) {
        log.info("智能推荐大学请求（用户ID：{}）：{}", userId, reqVO);
        
        try {
            CollegeRecommendRespVO result = collegeRecommendationService.recommendColleges(reqVO, userId);
            return success(result);
        } catch (Exception e) {
            log.error("智能推荐大学失败", e);
            return CommonResult.error(500, "推荐服务异常：" + e.getMessage());
        }
    }

    @GetMapping("/calculate-probability")
    @Operation(summary = "计算录取概率")
    public CommonResult<Double> calculateAdmissionProbability(
            @Parameter(description = "用户位次", required = true) @RequestParam Integer userRank,
            @Parameter(description = "学校UUID", required = true) @RequestParam String schoolUuid,
            @Parameter(description = "专业名称", required = true) @RequestParam String majorName,
            @Parameter(description = "省份", required = true) @RequestParam String province,
            @Parameter(description = "年份", required = true) @RequestParam Integer year,
            @Parameter(description = "考试类型", required = true) @RequestParam String examType) {
        
        try {
            Double probability = collegeRecommendationService.calculateAdmissionProbability(
                    userRank, schoolUuid, majorName, province, year, examType);
            return success(probability);
        } catch (Exception e) {
            log.error("计算录取概率失败", e);
            return CommonResult.error(500, "计算失败：" + e.getMessage());
        }
    }

    @GetMapping("/determine-type")
    @Operation(summary = "判断推荐类型")
    public CommonResult<String> determineRecommendationType(
            @Parameter(description = "录取概率", required = true) @RequestParam Double probability) {
        
        try {
            String type = collegeRecommendationService.determineRecommendationType(probability);
            return success(type);
        } catch (Exception e) {
            log.error("判断推荐类型失败", e);
            return CommonResult.error(500, "判断失败：" + e.getMessage());
        }
    }

    @PostMapping("/generate-reason")
    @Operation(summary = "生成推荐理由")
    public CommonResult<String> generateRecommendationReason(
            @Parameter(description = "学校名称", required = true) @RequestParam String schoolName,
            @Parameter(description = "专业名称", required = true) @RequestParam String majorName,
            @Parameter(description = "录取概率", required = true) @RequestParam Double probability,
            @Parameter(description = "推荐类型", required = true) @RequestParam String type,
            @Parameter(description = "学校标签") @RequestParam(required = false) java.util.List<String> tags) {
        
        try {
            String reason = collegeRecommendationService.generateRecommendationReason(
                    schoolName, majorName, probability, type, tags);
            return success(reason);
        } catch (Exception e) {
            log.error("生成推荐理由失败", e);
            return CommonResult.error(500, "生成失败：" + e.getMessage());
        }
    }

    /**
     * 优化请求参数，平衡性能和完整性
     */
    private CollegeRecommendReqVO optimizeRequestParameters(CollegeRecommendReqVO reqVO) {
        CollegeRecommendReqVO optimized = new CollegeRecommendReqVO();

        // 复制基本参数
        optimized.setProvince(reqVO.getProvince());
        optimized.setScore(reqVO.getScore());
        optimized.setRanks(reqVO.getRanks());
        optimized.setYear(reqVO.getYear());
        optimized.setClassify(reqVO.getClassify());
        optimized.setSubjects(reqVO.getSubjects());
        optimized.setBatch(reqVO.getBatch());
        optimized.setPageNum(reqVO.getPageNum());

        // 优化页面大小，避免一次性处理过多数据
        Integer pageSize = reqVO.getPageSize();
        if (pageSize == null || pageSize > 200) {
            optimized.setPageSize(200); // 限制最大200条
            log.info("页面大小优化：{} -> 200", pageSize);
        } else {
            optimized.setPageSize(pageSize);
        }

        return optimized;
    }

    /**
     * 创建快速推荐参数，优先响应速度
     */
    private CollegeRecommendReqVO createFastRequestParameters(CollegeRecommendReqVO reqVO) {
        CollegeRecommendReqVO fast = new CollegeRecommendReqVO();

        // 复制基本参数
        fast.setProvince(reqVO.getProvince());
        fast.setScore(reqVO.getScore());
        fast.setRanks(reqVO.getRanks());
        fast.setYear(reqVO.getYear());
        fast.setClassify(reqVO.getClassify());
        fast.setSubjects(reqVO.getSubjects());
        fast.setBatch(reqVO.getBatch());
        fast.setPageNum(reqVO.getPageNum());

        // 强制限制页面大小，确保快速响应
        fast.setPageSize(50); // 快速模式最多50条

        log.info("快速推荐参数优化：页面大小限制为50");

        return fast;
    }

    /**
     * 资源清理
     */
    public void shutdown() {
        try {
            recommendationExecutor.shutdown();
            if (!recommendationExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
                recommendationExecutor.shutdownNow();
                log.warn("推荐计算线程池强制关闭");
            } else {
                log.info("推荐计算线程池正常关闭");
            }
        } catch (InterruptedException e) {
            recommendationExecutor.shutdownNow();
            Thread.currentThread().interrupt();
            log.error("关闭推荐线程池时被中断", e);
        }
    }
}
